package com.example.rpc;

import com.example.protocol.PackMsg;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;
import java.util.Random;

/**
 * @ClassName ClientPool
 * @Description TODO
 * @Author: XMK
 * @Date: 2020/9/30 9:44
 * @Version: 1.0
 */
public class ClientPool {
    private NioSocketChannel[] channels;
    private Object[] locks;

    private Random rand = new Random();

    public ClientPool(int size) {
        channels = new NioSocketChannel[size];
        locks = new Object[size];

        for (int i = 0; i < size; i++) {
            locks[i] = new Object();
        }
    }

    public synchronized NioSocketChannel getClient(InetSocketAddress address) {

        int i = rand.nextInt(channels.length);
        NioSocketChannel channel = channels[i];
        if (channel != null && channel.isActive()) {
            return channel;
        }

        synchronized (locks[i]) {
            channels[i] = createNew(address);
            return channels[i];
        }
    }

    private NioSocketChannel createNew(InetSocketAddress address) {
        NioEventLoopGroup worker = new NioEventLoopGroup(1);
        Bootstrap bs = new Bootstrap();
        try {
//            System.out.println("create new NioSocketChannel in thread: " + Thread.currentThread().getName());
            return (NioSocketChannel)bs.group(worker)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new ServerDecoder());
                            pipeline.addLast(new MyResponseHandler());
                        }
                    })
                    .connect(address)
                    .sync()
                    .channel();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }

    private class MyResponseHandler extends ChannelInboundHandlerAdapter {

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            PackMsg packMsg = (PackMsg) msg;

//            System.out.println("client   == " + packMsg);
            ResponseHandler.runCallback(packMsg);

        }
    }
}
